package algorithm;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;

public class shuxueyunsuan {

    /**
     * 数学表达式
     *
     * 中缀表达式转后缀表达式:
     *
     * 通过“Shunting-Yard算法”将中缀表达式转换为后缀表达式。
     * 支持括号、运算符和函数。
     * 后缀表达式求值:
     *
     * 使用栈计算后缀表达式，支持四种运算符和函数（sin、cos、tan、sqrt）。
     *
     *  中缀表达式:
     *      (2 + 3) * 4
     *  转换为后缀表达式:
     *      2 3 + 4 *
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String str = scanner.nextLine();
            double res = parse(str);
            System.out.println(String.valueOf(Math.round(res)));
        }
        scanner.close();
    }


    public static void main1(String[] args) {
        List<String> expressions = new ArrayList<>();
        expressions.add("1+2*(37+(25*3))"); // -1
        expressions.add("1+2.0*sin(37+(25*3))");// -1
        expressions.add("(2+ 3.50)*4*sqrt( sin(1.5))");  // 22
        expressions.add("-3+4/ (2.5+3.7)");  // -2
        expressions.add("(-3+4)/2.5+3.9");  // 4
        expressions.add("1.2-3.5*5.2- 13.2");  // -30
        expressions.add("1.2-3.5*5.2- 13.7");  // -31
        expressions.add("2.3*5*7-12*9/8");  // 67
        expressions.add("-sin(3.5-sqrt(4)) + cos(tan(2.5))"); // 0
//        expressions.add("sqrt(4)"); // 2
//        expressions.add("tan(2.5)"); // -1
//        expressions.add("sin(3.5 - 4)"); // 2
//        expressions.add("cos(-1)"); // 0.9974949866040544
//        expressions.add("-sin(3.5-sqrt(4))"); //-0.9974949866040544
//        expressions.add("cos(tan(2.5))"); //0.7337153396568176
//        expressions.add("sin(1.5) + cos(0.747)"); // 0
//        expressions.add("cos(-0.747)"); // 0.7337304894890774
        for (String expression : expressions) {
            double parse = parse(expression);
            System.out.println(expression + "-> " + Math.round(parse));
//            System.out.println(expression + "-> " + (parse));
        }
    }

    public static double parse(String str) {
        // Preprocess the string to remove spaces
        str = str.replaceAll("\\s+", "");

        // Convert the infix expression to postfix using Shunting-Yard Algorithm
        List<String> postfix = toPostfix(str);

        // Evaluate the postfix expression
        return evaluatePostfix(postfix);
    }

    private static List<String> toPostfix(String expression) {
        Stack<String> operatorStack = new Stack<>();
        List<String> output = new ArrayList<>();
        StringBuilder numberBuffer = new StringBuilder();

        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);

            if (Character.isDigit(c) || c == '.') {
                numberBuffer.append(c);
            } else if (c == '-' && (i == 0 || expression.charAt(i - 1) == '(' || isOperator(expression.charAt(i - 1)))) {
                // Handle unary minus
                if (numberBuffer.length() > 0) {
                    output.add(numberBuffer.toString());
                    numberBuffer.setLength(0);
                }
                operatorStack.push("unary-");
            } else {
                if (numberBuffer.length() > 0) {
                    output.add(numberBuffer.toString());
                    numberBuffer.setLength(0);
                }

                if (c == '(') {
                    operatorStack.push("(");
                } else if (c == ')') {
                    while (!operatorStack.isEmpty() && !operatorStack.peek().equals("(")) {
                        output.add(operatorStack.pop());
                    }
                    operatorStack.pop(); // Pop the '('

                    // Check if a function is on top of the stack
                    if (!operatorStack.isEmpty() && isFunction(operatorStack.peek())) {
                        output.add(operatorStack.pop());
                    }
                } else if (isOperator(c)) {
                    while (!operatorStack.isEmpty() && precedence(operatorStack.peek()) >= precedence(String.valueOf(c))) {
                        output.add(operatorStack.pop());
                    }
                    operatorStack.push(String.valueOf(c));
                } else if (Character.isLetter(c)) {
                    StringBuilder funcBuffer = new StringBuilder();
                    while (i < expression.length() && Character.isLetter(expression.charAt(i))) {
                        funcBuffer.append(expression.charAt(i++));
                    }
                    i--; // Adjust the index after the loop
                    operatorStack.push(funcBuffer.toString());
                }
            }
        }

        if (numberBuffer.length() > 0) {
            output.add(numberBuffer.toString());
        }

        while (!operatorStack.isEmpty()) {
            output.add(operatorStack.pop());
        }

        return output;
    }
    private static double evaluatePostfix(List<String> postfix) {
        Stack<Double> valueStack = new Stack<>();

        for (String token : postfix) {
            if (isNumber(token)) {
                valueStack.push(Double.parseDouble(token));
            } else if (isFunction(token)) {
                double arg = valueStack.pop();
                switch (token) {
                    case "sin":
                        valueStack.push(Math.sin( (arg)));
                        break;
                    case "cos":
                        valueStack.push(Math.cos( (arg)));
                        break;
                    case "tan":
                        valueStack.push(Math.tan( (arg)));
                        break;
                    case "sqrt":
                        valueStack.push(Math.sqrt(arg));
                        break;
                }
            } else if (token.equals("unary-")) {
                double arg = valueStack.pop();
                valueStack.push(-arg);
            } else if (isOperator(token.charAt(0))) {
                double b = valueStack.pop();
                double a = valueStack.isEmpty() ? 0 : valueStack.pop(); // Handle unary minus
                switch (token.charAt(0)) {
                    case '+':
                        valueStack.push(a + b);
                        break;
                    case '-':
                        valueStack.push(a - b);
                        break;
                    case '*':
                        valueStack.push(a * b);
                        break;
                    case '/':
                        valueStack.push(a / b);
                        break;
                }
            }
        }

        return valueStack.pop();
    }

    private static boolean isNumber(String token) {
        try {
            Double.parseDouble(token);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private static boolean isFunction(String token) {
        return token.equals("sin") || token.equals("cos") || token.equals("tan") || token.equals("sqrt");
    }

    private static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    private static int precedence(String operator) {
        switch (operator) {
            case "+":
            case "-":
                return 1;
            case "*":
            case "/":
                return 2;
            case "unary-":
                return 3; // Unary minus has higher precedence than binary operators
            default:
                return 0;
        }
    }

}
